package com.jay.studyproject.interview;

/**
 * 性能优化
 */
public class Demo3 {
    /**
     * 一、内存泄露(Memory Leak)如何查看和解决?
     * 概念：有些对象只有有限的生命周期，当他们的任务完成之后，它们将被垃圾回收，如果在对象的生命周期本该结束的时候，这个对象还被一系列的引用，这就会导致内存泄露。
     * 解决方法：使用开源框架LeakCanary检测针对性解决
     * 常见的内存泄露有：
     * 1.单例造成的内存泄露，例如单例中的Context生命周期大于本身Context生命周期
     * 2.线程使用Hander造成的内存泄漏，当activity已经结束，线程依然在运行更新UI
     * 3.非静态类使用静态变量导致无法回收释放造成泄露
     * 4.WebView网页过多造成内存泄露
     * 5.资源未关闭造成泄露，例如数据库使用完之后关闭连接
     *
     * 二、ANR是什么?怎样避免和解决ANR?
     * Application Not Responding，即应用无响应，出现的原因有三种：
     * a）KeyDispatchTimeout（5 seconds）主要类型按键或触摸事件在特定时间内无响应
     * b）BroadcastTimeout（10 seconds）BoradcastReceiver在特定的时间内无法处理
     * c）ServiceTimeout（20 seconds）小概率类型Service在特定的时间内无法处理完成
     * 避免ANR最核心的一点就是在主线程减少耗时操作。通常需要从那个以下几个方案下手：
     * 使用子线程处理耗时IO操作
     * 降低子线程优先级，使用Thread或者HandlerThread时，调用Process.setThreadPriority（Process.THREAD_PRIORITY_BACKGROUND）设置优先级，
     * 否则仍然会降低程序响应，因为默认Thread的优先级和主线程相同
     * 使用Handler处理子线程结果，而不是使用Thread.wait()或者Thread.sleep()来阻塞主线程
     * Activity的onCreate和onResume回调中尽量避免耗时的代码
     * BroadcastReceiver中onReceiver代码也要尽量减少耗时操作，建议使用intentService处理。intentService是一个异步的，会自动停止的服务，
     * 很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题
     *
     * 三、Android性能优化？
     * 布局优化: 减少布局层级，使用ViewStub提高显示速度，布局复用，尽可能少使用warp_content，删除空间中无用的属性,
     * 避免过度绘制移除window默认背景，按需显示占位图，自定义View优化，
     * 使用canvas.clipRect()识别可见区域
     * 启动速度:采用分布加载，异步加载，延期加载提高应用初始化速度，采用线程初始化数据等，合理的刷新机制
     * 内存方面:防止内存泄露,使用一些第三方工具检测解决
     * 代码优化:遵循Java生命周期
     * 安装包优化:删除无用资源，优化图片，代码混淆，避免重复库存在，插件化
     *
     * 四、谈谈你对Android性能优化方面的了解？
     *  布局优化
     * ● 页面减少层级嵌套，当页面层级嵌套太多时容易出现过度绘制（OverDraw）的现象，从而造成卡顿，我们可以通过使用约束布局（ConstraintLayout），
     * 相对布局（RelativeLayout），当然还可以根据情况使用viewStub，merg以及include来减少层级嵌套；
     * ● 在UI线程中，我们尽量避免在主线程中执行耗时的任务，通过在子线程执行通知UI线程更新布局；
     * ● 自定义View或ViewGroup时，避免在draw的过程中创建对象，从而导致在绘制的过程中创建多个对象导致内存抖动甚至内存溢出的情况；
     * ● 在View中使用属性动画时，在执行完动画必须移除动画。
     * 线程优化
     * ● 使用线程池（ThreadPool）完成线程的创建，避免创建过多的空闲线程从而使得大量空闲线程闲置或者被回收（GC），影响性能。
     * ● 自定义线程策略，对线程的失败的执行操作自定义策略完成因线程被拒绝无法执行导致任务不能执行；
     * ● 创建线程工厂（ThreadFactory）对线程进行重命名；
     * ● 建议使用Rxjava实现线程调度，如果使用Handler尽量避免Handler内部类持有大对象引发内存泄露的问题。
     * 网络优化
     * ● 第一次请求网络的时候保存并添加时间戳，从而判断数据是否过期，避免重复请求网络数据。常见的数据持久化的方法有数据库（Sqlite），SharePreference，File；
     * ● 根据情况Http/Https请求使用Cache-Control，以及设置max-age；
     * ● 使用Json方式，减少数据量从而减少流量消耗；
     * ● 图片压缩上传与加载，减少内存消耗的同时也可以减少流量的消耗。
     * 电量优化
     * ● 避免重复的进行网络请求以及多次重复加载网络图片或者H5页面；
     * ● 避免使用Service、BroadcastReceiver，使用后必须及时销毁；
     * ● 及时关闭蓝牙等硬件设备；
     * ● 避免长期唤醒屏幕，在合适的位置销毁。
     * 代码优化
     * ● 代码规范建议使用阿里巴巴的编码规则，在Android Studio中安装插件，打开实时检测功能；
     * ● 尽量避免使用内部类的方式，使用时需要销毁对应的对象，或者使用软引用（SoftReference）和弱引用的（WeakReference）方式，
     * 在合适的位置回收，比如onDestroy或者onStop中；
     * ● 使用MVP或者MVVM架构，在这里建议使用MVVM结合DataBinding，完成解耦，使用LiveData监听ViewModel层的数据变化；
     * ● 功能模块化或者插件化，创建多个Module；
     * ● 熟悉并掌握Java设计模式，运用到项目中有着事半功倍的效果。
     * 内存优化
     * ● 循环尽量不使用局部变量
     * ● 避免在onDraw中创建对象，onDraw会被频繁调用，容易造成内存抖动。循环中创建大的对象，也是如此。
     * ● 不用的对象及时释放
     * ● 数据库的cursor及时关闭
     * ● adapter使用缓存
     * ● 注册广播后，在生命周期结束时反注册
     * ● 及时关闭流操作
     * ● 图片尽量使用软引用，较大的图片可以通过 bitmapFactory 缩放后再使用，并及时recycler。
     * 另外加载巨图时不要使用 setImageBitmap 或 setImageResourse 或BitmapFactory.decodeResource，
     * 这些方法拿到的都是 bitmap 的对象，占用内存较大。可以用 BitmapFactory.decodeStream 方法配合 BitmapFactory.Options 进行缩放。
     * ● 避免 static 成员变量引用资源耗费过多实例
     * ● 避免静态内部类的引用
     * apk优化
     * 资源文件优化，代码优化，lint检查，.9.png，合理使用 shape 替代图片，webp等）
     * 启动优化
     * application中不要做大量耗时操作,如果必须的话，建议异步做耗时操作。
     *
     * 五、一般什么情况下会导致内存泄漏问题？
     * 内存泄露(Memory Leak)就是指该被GC垃圾回收的，但被一个生命周期比它长的对象仍然在引用它，导致无法回收，造成内存泄露，过多的内存泄露会导致OOM。
     * 1）非静态内部类、匿名内部类：非静态内部类、匿名内部类 都会持有外部类的一个引用，如果有一个静态变量引用了非静态内部类或者匿名内部类，
     * 导致非静态内部类或者匿名内部类的生命周期比外部类（Activity）长，就会导致外部类在该被回收的时候，无法被回收掉，引起内存泄露, 除非外部类被卸载。
     * 解决办法：将非静态内部类、匿名内部类改成静态内部类，或者直接抽离成一个外部类。 如果在静态内部类中，需要引用外部类对象，那么可以将这个引用封装在一个WeakReference(弱引用)中。
     * 2）静态的View：当一个Activity经常启动，但是对应的View读取非常耗时，我们可以通过静态View变量来保持对该Activity的rootView引用。
     * 这样就可以不用每次启动Activity都去读取并渲染View了。但View attach到我们的Window上，就会持有一个Context(即Activity)的引用。而我们的View有事一个静态变量，所以导致Activity不被回收。
     * 解决办法： 在使用静态View时，需要确保在资源回收时，将静态View detach掉。
     * 3）Handler：在Activity中定义Handler对象，那么Handler持有Activty的引用。而每个Message对象是持有Handler的引用的（Message对象的target属性持有Handler引用），
     * 从而导致Message间接引用到了Activity。如果在Activty destroy之后，消息队列中还有Message对象，Activty是不会被回收的。
     * 解决办法：将Handler放入单独的类或者将Handler放入到静态内部类中（静态内部类不会持有外部类的引用）。如果想要在handler内部去调用所在的外部类Activity，
     * 可以在handler内部使用弱引用的方式指向所在Activity，在onDestory时，调用相应的方法移除回调和删除消息。
     * 4）监听器（各种需要注册的Listener，Watcher等）：当我们需要使用系统服务时，比如执行某些后台任务、为硬件访问提供接口等等系统服务。我们需要把自己注册到服务的监听器中。
     * 然而，这会让服务持有 activity 的引用，如果程序员忘记在 activity 销毁时取消注册，那就会导致 activity 泄漏了。
     * 解决办法：在onDestory中移除注册
     * 5）资源对象没关闭造成内存泄漏：当我们打开资源时，一般都会使用缓存。比如读写文件资源、打开数据库资源、使用Bitmap资源等等。当我们不再使用时，应该关闭它们，使得缓存内存区域及时回收。
     * 解决办法：使用try finally结合，在try块中打开资源，在finally中关闭资源
     * 6）属性动画：在使用ValueAnimator或者ObjectAnimator时，如果没有及时做cancel取消动画，就可能造成内存泄露。因为在cancel方法里，最后调用了endAnimation(); ，在endAnimation里，有个AnimationHandler的单例，会持有属性动画对象的引用。
     * 解决办法：在onDestory中调用动画的cancel方法
     * 7） RxJava：在使用RxJava时，如果在发布了一个订阅后，由于没有及时取消，导致Activity/Fragment无法销毁，导致的内存泄露。
     * 解决办法：使用RxLifeCycle
     * 8）多线程相关的匿名内部类和非静态内部类：匿名内部类同样会持有外部类的引用，如果在线程中执行耗时操作就有可能发生内存泄漏，导致外部类无法被回收，直到耗时任务结束，
     * 解决办法是在页面退出时结束线程中的任务
     * 9）Context 导致内存泄漏:根据场景确定使用 Activity 的 Context 还是 Application 的 Context,因为二者生命周期不同，对于不必须使用 Activity 的 Context 的场景（Dialog）,一律采用Application 的 Context,单例模式是最常见的发生此泄漏的场景，比如传入一个 Activity 的 Context 被静态类引用，导致无法回收
     * 10）WebView 导致的内存泄漏:WebView 只要使用一次，内存就不会被释放，所以 WebView 都存在内存泄漏的问题，通常的解决办法是为 WebView 单开一个进程，使用 AIDL 进行通信，根据业务需求在合适的时机释放掉
     * 11）集合中的对象未清理:集合用于保存对象，如果集合越来越大，不进行合理的清理，尤其是入股集合是静态的
     * 12）Bitmap 导致内存泄漏
     * bitmap 是比较占内存的，所以一定要在不使用的时候及时进行清理，避免静态
     * 变量持有大的bitmap 对象
     *
     * 六、自定义Handler 时如何有效地避免内存泄漏问题？
     * 问题原因：一般非静态内部类持有外部类的引用的情况下，造成外部类在使用完成后不能被系统回收内存，从而造成内存泄漏。
     * 这里 Handler 持有外部类 Activity 的引用，一旦 Activity 被销毁，而此时 Handler 依然持有 Activity 引用，就会造成内存泄漏。
     * 解决方案：将 Handler 以静态内部类的形式声明，然后通过弱引用的方式让 Handler 持有外部类 Activity 的引用，这样就可以避免内存泄漏问题了：
     * 1.自定义的静态handler
     * 2.可以加一个弱引用
     * 3.还有一个主意的就是当你activity被销毁的时候如果还有消息没有发出去 就remove掉吧
     * 4.removecallbacksandmessages去清除Message和Runnable 加null 写在生命周的ondestroy()就行
     *
     * 七、哪些情况下会导致oom问题？
     * 1,过多的内存泄漏会导致内存溢出 2,加载大的图片 3,创建过多的线程
     * 内存优化的解决方法：
     * 1.申请更大的内存，比如多进程、设置manifest中的largeHeap=true等。
     * 2.减少内存使用
     * ①使用优化后的集合对象，分场景使用SpaseArray和HashMap；
     * ②使用微信的mmkv替代sharedpreference；
     * ③使用StringBuilder替代String拼接
     * ④统一带有缓存的基础库，特别是图片库，如果用了两套不一样的图片加载库就会出现2个图片各自维护一套图片缓存
     * ⑤给ImageView设置合适尺寸的图片，列表页显示缩略图，查看大图显示原图 ⑥优化业务架构设计，比如省市区数据分批加载，
     * 需要加载省就加载省，需要加载市就加载失去，避免一下子加载所有数据 3.避免内存泄漏
     * 八、ANR 出现的场景以及解决方案？
     * ANR:Application Not Responding，即应用无响应
     * ANR一般有三种类型：
     * 1：KeyDispatchTimeout(5 seconds) –主要类型按键或触摸事件在特定时间内无响应
     * 2：BroadcastTimeout(10 seconds)BroadcastReceiver在特定时间内无法处理完成
     * 3：ServiceTimeout(20 seconds) –小概率类型Service在特定的时间内无法处理完成
     * 超时的原因一般有两种：
     * (1)当前的事件没有机会得到处理（UI线程正在处理前一个事件没有及时完成或者looper被某种原因阻塞住）
     * (2)当前的事件正在处理，但没有及时完成
     * UI线程尽量只做跟UI相关的工作，耗时的工作（数据库操作，I/O，连接网络或者其他可能阻碍UI线程的操作）放入单独的线程处理，尽量用Handler来处理UI thread和thread之间的交互。
     * 解决方式：
     * (1)不要在主线程中做耗时的操作，而应放在子线程中来实现。如onCreate()和onResume()里尽可能少的去做创建操作。
     * (2)应用程序应该避免在BroadcastReceiver里做耗时的操作或计算。
     * (3)避免在Intent Receiver里启动一个Activity，因为它会创建一个新的画面，并从当前用户正在运行的程序上抢夺焦点。
     * (4)service是运行在主线程的，所以在service中做耗时操作，必须要放在子线程中。
     * 九、谈谈Android中内存优化的方式？
     * 关于内存泄漏，一般像单例模式的使用不当啊、集合的操作不当啊、资源的缺乏有效的回收机制啊、Handler、线程的使用不当等等都有可能引发内存泄漏。
     * 1）单例模式引发的内存泄漏：
     * 原因：单例模式里的静态实例持有对象的引用，导致对象无法被回收，常见为持有Activity的引用
     * 优化：改为持有Application的引用，或者不持有使用的时候传递。
     * 2）集合操作不当引发的内存泄漏：
     * 原因：集合只增不减
     * 优化：有对应的删除或卸载操作
     * 3）线程的操作不当引发的内存泄漏：
     * 原因：线程持有对象的引用在后台执行，与对象的生命周期不一致
     * 优化：静态实例+弱引用(WeakReference)方式，使其生命周期一致
     * 4）匿名内部类/非静态内部类操作不当引发的内存泄漏：
     * 原因：内部类持有对象引用，导致无法释放，比如各种回调
     * 优化：保持生命周期一致，改为静态实例+对象的弱引用方式（WeakReference）
     * 5）常用的资源未关闭回收引发的内存泄漏：
     * 原因：BroadcastReceiver，File，Cursor，IO流，Bitmap等资源使用未关闭
     * 优化：使用后有对应的关闭和卸载机制
     * 6）Handler 使用不当造成的内存泄漏：
     * 原因：Handler持有Activity的引用，其发送的 Message 中持有 Handler 的引用，当队列处理 Message 的时间过长会导致 Handler 无法被回收
     * 优化：静态实例+弱引用(WeakReference)方式
     * 7）内存溢出：
     * 原因：内存泄漏长时间的积累；业务操作使用超大内存；
     * 优化：调整图像大小后再放入内存、及时回收；不要过多的创建静态变量；
     * 十、谈谈布局优化的技巧？
     * 1.减少过度绘制，减少不必要的背景绘制,线性，相对，约束层级一样的用线性，层级多的用相对或者约束来控制，减少层级 2.减少布局深层次嵌套，配合merge，include，viewStub，约束布局这些来减少布局的开销 3.尽量减少控件个数，对 TextView 左边或者右边有图片可是试用 drawableLeft，drawableRight 4.熟悉API尽量借助系统现有的属性来实现一些UI效果 5.对于 ImageVIew 通过imageDrawable方法进行设置避免ImageView的background和imageDrawable重叠 6.使用Canvas的clipRect和clipPath方法限制View的绘制区域
     * 十一、Android 中的图片优化方案？
     * 首先我们可以对图片进行二次采样，从本质上减少图片的内存占用。就是将大图片缩小之后放入到内存中，以实现减小内存的目的 2.其次就是采用三层缓存架构，提高图片的访问速度。三层缓存架构是内存-文件-网络。
     * 内存是访问速度最快的部分但是分配的空间有限，所以不可能占用太多。其中内存缓存可以采用LRU算法（最近最少使用算法），来确定要删除内存中的那些图片，保存那
     * 些图片。
     * 文件就是将图片保存到本地，可以使SD卡中，也可以是手机内部存储中。
     * 网络就是访问网络下载图片，进行图片的加载。 3.常见的png，JPG，webp等格式的图片在设置到UI上之前需要经过解码过程，而图片采用不同的码率，也会造成对内存的占用不同。 4.最后一点，也是图片优化最重要的一点。重用Bitmap. 5.不使用bitmap要记得实时回收，减小内存的开销

     * 十二、Android Native Crash问题如何分析定位？
     * 1. Android自带工具 ndk-stack 通过崩溃信息精准定位崩溃位置
     * ① 先将崩溃信息保存为文件，再通过文件还原
     * adb logcat -c
     * adb logcat > crash.log
     * ndk-stack -sym app/build/intermediates/cmake/debug/obj/x86/ -dump crash.log
     * ② 直接在logcat 中还原
     *     adb logcat -c
     *     adb logcat | ndk-stack -sym app/build/intermediates/cmake/debug/obj/x86
     *
     * l -sym 后的参数为 当前运行环境的符号库目录
     * l projectName 为项目目录, app 为分析的 项目module
     * l armeabi 为当前APP运行环境(手机或模拟器的环境)的CPU架构 ：armeabi、arm64-v8a、armeabi-v7a、x86、x86_64
     * 日志分析：
     * ndk-stack -sym projectName\app\build\intermediates\cmake\debug\obj\armeabi -i log.txt
     * 2. 通过DropBox 日志解析
     * Android Dropbox 是 Android 在 Froyo(API level 8) 引入的用来持续化存储系统数据的机制。主要用于记录 Android 运行过程中, 内核, 系统进程, 用户进程等出现严重问题时的 log, 可以认为这是一个可持续存储的系统级别的 logcat。
     * 相关文件记录存储目录：/data/system/dropbox
     * 具体的方法和行数可以用Android/SDK/NDK 提供的工具 linux-android-addr2line 来进一步定位。
     * 3.通过 BreakPad 捕获解析
     * BreakPad 是 Google 开发的一个跨平台 C/C++ dump捕获开源库，崩溃文件使用微软的 minidump格式存储，也支持发送这个 dump 文件到你的服务器，breakpad 可以在程序崩溃时触发 dump 写入操作，也可以在没有触发 dump 时主动写 dump 文件。breakpad 支持 windows、linux、macos、android、ios 等。
     * 十三、谈谈怎么给apk瘦身？
     * 1. 代码方面
     * 保持良好的编程习惯，不要重复或者不用的代码，谨慎添加libs，移除使用不到的libs。
     * 使用proguard混淆代码，它会对不用的代码做优化，并且混淆后也能够减少安装包的大小。
     * native code的部分，大多数情况下只需要支持armabi与x86的架构即可。如果非必须，可以考虑拿掉x86的部分。
     * 2. 资源方面
     * 使用Lint工具查找没有使用到的资源。去除不使用的图片，String，XML等等。 assets目录下的资源请确保没有用不上的文件。
     * 生成APK的时候，aapt工具本身会对png做优化，但是在此之前还可以使用其他工具如tinypng对图片进行进一步的压缩预处理。
     * jpeg还是png，根据需要做选择，在某些时候jpeg可以减少图片的体积。 对于9.png的图片，可拉伸区域尽量切小，另外可以通过使用9.png拉伸达到大图效果的时候尽量不要使用整张大图。
     * 3. 策略方面
     * 有选择性的提供hdpi，xhdpi，xxhdpi的图片资源。建议优先提供xhdpi的图片，对于mdpi，ldpi与xxxhdpi根据需要提供有差异的部分即可。
     * 尽可能的重用已有的图片资源。例如对称的图片，只需要提供一张，另外一张图片可以通过代码旋转的方式实现。
     * 能用代码绘制实现的功能，尽量不要使用大量的图片。例如减少使用多张图片组成animate-list的AnimationDrawable，这种方式提供了多张图片很占空间。
     *
     *
     * 十四、谈谈你是如何优化App启动过程的？
     * 1.把application oncreate 中要执行的方法 分为同步和异步,尽量去延迟执行 或者使用空闲线程 去初始化一些方法
     * 2.配置一个启动背景,避免白屏或者黑屏,然后做一个空的Activity这个Activity只做一件事,就是跳转到真的Activity,
     * 因为 启动速度 和application oncreate的耗时和第一个Activity的绘制有关, 上面都是easy的做法
     * 利用 redex 工具 优化 dex , 因为 class字节码 分布在不同的dex中,所以启动的时候必须逐个查找一些文件,他们散列分布在不同的dex中,
     * 查找起来耗时又不方便,利用redex 把相关的class 放在同一个dex包下,避免 同一个dex包被多次查找
     * 4.在attachedbaseContext中 新起一个进程 去加载 mutildex 可以加速App启动页的打开(可能在启动页中会等待,但是加速了从launcher到启动页的速度)
     *
     * 十五、谈谈代码混淆的步骤？
     * 为什么要混淆
     * 1.防止我们的apk别轻易地反编译.
     * 2.混淆代码可以简化我们的apk大小.
     * Studio混淆:
     * 1.开启混淆
     * 需要更改build.gradle(Model:app)中的一个配置( minifyEnabled 默认是false,不混淆. 改为true即开启混淆
     * proguardFiles 混淆文件的位置)
     * 2.混淆文件
     * 3.自定义混淆规则
     * 在proguard-rules.pro中写我们的混淆规则.
     *
     * 十六、谈谈App的电量优化？
     * ·  避免轮循。可以利用推送。如果非要轮循，合理的设置频率。
     * ·  应用处于后台时，避免某些数据的传输，比如感应器，定位，视频缓存。
     * ·  页面销毁时，取消掉网络请求。
     * ·  限制访问频率，失败后不要无限的重连。
     * ·  合理的选择定位精度和频率。
     * ·  使用缓存。如果数据变化周期比较长，可以出一个配置接口，用于记录那些接口有变化。没变化的直接用缓存。
     * ·  减少广播的使用频率。可以用观察者，startActivityForResult等代替。
     * 十七、谈谈如何对WebView进行优化？
     * 1 、从webview入手，减少加载时间或者说复用加载时间
     * 全局WebView
     * 方法：
     * 在客户端刚启动时，就初始化一个全局的WebView待用，并隐藏；
     * 当用户访问了WebView时，直接使用这个WebView加载对应网页，并展示。
     * 这种方法可以比较有效的减少WebView在App中的首次打开时间。当用户访问页面时，不需要初始化WebView的时间。
     * 当然这也带来了一些问题，包括：
     * 额外的内存消耗。
     * 页面间跳转需要清空上一个页面的痕迹，更容易内存泄露。
     * 客户端代理数据请求
     * 方法：
     * 在客户端初始化WebView的同时，直接由native开始网络请求数据；
     * 当页面初始化完成后，向native获取其代理请求的数据。
     * 此方法虽然不能减小WebView初始化时间，但数据请求和WebView初始化可以并行进行，总体的页面加载时间就缩短了；缩短总体的页面加载时间：
     * 还有其他各种优化的方式，不再一一列举，总结起来都是围绕两点：
     * 1. 在使用前预先初始化好WebView，从而减小耗时。
     * 2. 在初始化的同时，通过Native来完成一些网络请求等过程，使得WebView初始化不是完全的阻塞后续过程。
     * 2、资源本地化
     * 在webview的加载过程中，我们通过重写方法 shouldInterceptRequest 可以拦截到不同的请求
     * 只需要把一些常用的资源如cs、js文件打包到apk中，然后做本地的替换，就回使用本地的资源，这样减少了重复请求的时间，优化了webview的加载时间
     * 3、本地离线包的形式
     * webview 可以加载网络资源，那么也是可以加载本地的资源，在apk 启动的时候，我们可以把整个前端代码文件下载解压到本地的文件路径中，然后通过file：///...index.html 去打开本地的资源
     * 4、拦截webview的请求，shouldInterceptRequest 不仅可以拦截资源文件，也是可以拦截html中的ajax请求，拦截请求后，可以使用android常见的okhttp或者retrofit等请求框架发起请求，可以添加需要的头信息，或者修改请求参数，然后返回response再返回给webview，这样就做到了动态修改webview中的请求信息，这里需要注意的是，post请求的body是无法拦截的到的，所以就需要把body参数放置到header中拦截，然后自己处理后再拼装即可
     * 十八、如何处理大图的加载？
     * 1、普通设置方法设置大图片是否会导致界面崩溃，多大的图片才会导致崩溃
     * 答：会发生异常，加载的图片数据内存大于100M会发生RuntimeException异常，系统框架未处理的情况会发生崩溃
     * 因为Android系统就是这样限制的。
     * 一般来说加载几M的图片没啥问题，但是加载十几M以上的图片就会有异常，出现图片不加载或者界面崩溃或者应用崩溃的现象。
     * 2、如何保证加载大图不发生崩溃
     * 答：可设置options.inSampleSize设置采样率和options.inPreferredConfig降低图片分辨率达到减少内存加载的目的
     * 3、Glide设置显示大图是否会发生崩溃
     * Glide加载大图不会发生崩溃
     * Glide里面会加载两次图片
     * 第一次读取配置，比如图片原生宽高，设置options.inJustDecodeBounds属性设置为true，不占用内存
     * 第二次结合布局的宽高设置图片设置理想的采样率比例。
     * 4、大图缩放滑动如何实现
     * （1）写一个自定义View加载图片
     * （2）设置setImage方法设置图片，测量图片宽高
     * （3）调用requestLayout()重新加载图片
     * （4）在onMeasure(...)方法中对比图片宽高和View的宽高，
     * （5）定义使用区域解码器、手势对象、缩放手势，缩放因子等对象
     * （6）在onDraw(...)做对应的缩放和区域滑动
     * 5、大图缩放和滑动框架的使用
     * 大图处理神器： SubsamplingScaleImageView 框架
     * （1）定义缩放图片对象
     * SubsamplingScaleImageView imageView = (SubsamplingScaleImageView)findViewById(R.id.image); //自定义View
     * （2）缩放图片对象中放入图片数据
     * imageView.setImage(ImageSource.resource(R.mipmap.test_22m)); //使用ImageSource的静态方法转换成ImageSource对象，加载到View中即可
     * 十九、谈谈如何对网络请求进行优化？
     * 1.为避免DNS解析异常问题，可以直接使用 IP 建立连接；
     * 2.使用 Gzip 压缩 Response 减少数据传输量；使用 Protocol Buffer 代替 JSON；
     * 3.请求图片的 url 中可以添加 格式、质量、宽高等参数；使用缩略图、使用 WebP格式图片，大图分片传输；
     * 4.使用网络缓存，使用图片加载框架；
     * 5.监听设备网络状态，根据不同网络状态选择对应情况下的网络请求策略：网络良好和弱网、离线等情况下分别设计不同的请求策略，
     * 比如 WIFI 下一个请求可以获取几十个数据，甚至可以一次性执行多个请求；而弱网下一个请求获取几个数据，且文本类型优先，富文本其次，
     * 除文本数据外其它类型的数据一开始只显示占位符；离线下事先保存请求数据到磁盘，在离线时从磁盘加载数据。
     *
     * 二十、请谈谈如何加载Bitmap并防止内存溢出？
     * (Bitmap占用内存大小的计算公式为：图片宽度×图片高度×一个像素点所占字节数
     * Drawable：通用的图形对象，用于装载常用格式的图像，既可以是PNG，JPG这样的图像， 也是前面学的那13种Drawable类型的可视化对象！我们可以理解成一个用来放画的——画框！
     * Bitmap(位图)：我们可以把他看作一个画架，我们先把画放到上面，然后我们可以 进行一些处理，比如获取图像文件信息，做旋转切割，放大缩小等操作！
     * Canvas(画布)：如其名，画布，我们可以在上面作画(绘制)，你既可以用Paint(画笔)， 来画各种形状或者写字，又可以用Path(路径)来绘制多个点，然后连接成各种图形！
     * Matrix(矩阵)：用于图形特效处理的，颜色矩阵(ColorMatrix)，还有使用Matrix进行图像的 平移，缩放，旋转，倾斜等！
     * 减小内存占用
     * 1.BitmapFactory.Options.inSampleSize
     * inSampleSize 是BitmapFactory.Options的一个属性，改变该配置即改变图片的宽高，如果设置为大于1的值（小于1的值即为1），则请求解码器对原始图像进行二次采样，返回较小的图像以节省内存。
     * 2.BitmapFactory.Options.inPreferredConfig
     * inPreferredConfig 是BitmapFactory.Options的一个属性，其默认值为 Bitmap.Config.ARGB_8888，改变该配置，可改变一个像素点占用字节数
     * 该属性常用配置如下，A代表透明度，R代表红色，G代表绿色，B代表蓝色
     *
     * 二十一、谈谈RecyclerView的缓存机制？
     *
     * 二十二、内存泄漏和内存溢出区别？
     * 内存溢出(out of memory)：是指程序在申请内存时，没有足够的内存空间供其使用，出现 out of memory；比如申请了一个 integer，但给它存了 long 才能存下的数，那就是内存溢
     * 出。
     * 内存泄露(memory leak)：是指程序在申请内存后，无法释放已申请的内存空间，一次内存泄露危害可以忽略，但内存泄露堆积后果很严重，无论多少内存,迟早会被占光。memory leak
     * 会最终会导致out of memory
     * 查找内存泄漏可以使用Android Studio 自带的AndroidProfiler 工具或 MAT ,内存泄露检测工具:LeakCanary
     *
     * 二十三、说下冷启动与热启动是什么，区别，如何优化，使用场景等
     * app冷启动： 当应用启动时，后台没有该应用的进程，这时系统会重新创建一个新的进程分配给该应用， 这个启动方式就叫做冷启动（后台不存在该应用进程）。
     * 冷启动因为系统会重新创建一个新的进程分配给它，所以会先创建和初始化Application类，再创建和初始化MainActivity类（包括一系列的测量、布局、绘制），最后显示在界面上。
     * app热启动： 当应用已经被打开， 但是被按下返回键、Home键等按键时回到桌面或者是其他程序的时候，再重新打开该app时， 这个方式叫做热启动（后台已经存在该应用进程）。热启动因为会从已有的进程中来启动，
     * 所以热启动就不会走Application这步了，而是直接走MainActivity（包括一系列的测量、布局、绘制），所以热启动的过程只需要创建和初始化一个MainActivity就行了，而不必创建和初始化Application
     * 冷启动的流程
     * 当点击app的启动图标时，安卓系统会从Zygote进程中fork创建出一个新的进程分配给该应用，之后会依次创建和初始化Application类、创建MainActivity类、
     * 加载主题样式Theme中的windowBackground等属性设置给MainActivity以及配置Activity层级上的一些属性、再inflate布局、
     * 当onCreate/onStart/onResume方法都走完了后最后才进行contentView的measure/layout/draw显示在界面上
     * 冷启动的生命周期简要流程：
     * Application构造方法 –> attachBaseContext()–>onCreate –>Activity构造方法 –> onCreate() –> 配置主体中的背景等操作 –>onStart() –> onResume() –> 测量、布局、绘制显示
     *
     * 冷启动的优化主要是视觉上的优化，解决白屏问题，提高用户体验，所以通过上面冷启动的过程。能做的优化如下：
     * 减少onCreate()方法的工作量
     * 不要让Application参与业务的操作
     * 不要在Application进行耗时操作
     * 不要以静态变量的方式在Application保存数据
     * 减少布局的复杂度和层级
     * 减少主线程耗时
     *
     */
}
